WebView拦截history.back的正确姿势

您所在的位置:网站首页 js 拦截器重定向 WebView拦截history.back的正确姿势

WebView拦截history.back的正确姿势

2024-01-19 07:51| 来源: 网络整理| 查看: 265

一、问题场景

总的来说,Webview的页面加载可分为四种流程。

正常流程: normal.png 重定向(302)流程: redirect.png 内部跳转(location.href)流程: location href.png 历史栈回退(history.back)流程:

history.back.png

其中,历史栈回退流程比较特殊。这是因为,历史栈回退首先触发的是shouldInterceptRequest,而非loadUrl或shouldOverrideUrlLoading。

private String loadUrl; public boolean shouldOverrideUrlLoading(WebView view, String url) { loadUrl = url; return false; } @Override public void loadUrl(String url) { loadUrl = url; super.loadUrl(url); } public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) { String url = request.getUrl().toString(); if (loadUrl.equals(url)) { //进行拦截处理 } return null; }

这使得对WebView页面加载进行拦截处理时,由于缺少了loadUrl和shouldOverrideUrlLoading提前告知页面loadUrl的过程,而页面(loadUrl)、各种资源(js、css、jpg等)以及业务请求(ajax)都会先在shouldInterceptRequest中回调后再执行加载,从而无法确定当前要加载的url是不是需要拦截的loadUrl,变得非常棘手。

如果一定要对history.back进行拦截,那该怎么办呢?经过一番折腾终于解决了问题,鉴于网上(google keywords: webview dectect history.back)也有一些同行遇到了相同问题,却未看到有人给出行之有效的解决方案,于是将在下文撰写我的解决办法。

二、WebView栈列表

WebView提供了一个获取栈列表WebBackForwardList的方法,

copyBackForwardList()

WebBackForwardList源码的javadoc描述里非常清晰地说明了这点。

/** * This class contains the back/forward list for a WebView. * WebView.copyBackForwardList() will return a copy of this class used to * inspect the entries in the list. */ public abstract class WebBackForwardList implements Cloneable, Serializable { /** * Return the current history item. This method returns {@code null} if the list is * empty. * @return The current history item. */ @Nullable public abstract WebHistoryItem getCurrentItem(); /** * Get the index of the current history item. This index can be used to * directly index into the array list. * @return The current index from 0...n or -1 if the list is empty. */ public abstract int getCurrentIndex(); /** * Get the history item at the given index. The index range is from 0...n * where 0 is the first item and n is the last item. * @param index The index to retrieve. */ public abstract WebHistoryItem getItemAtIndex(int index); /** * Get the total size of the back/forward list. * @return The size of the list. */ public abstract int getSize(); /** * Clone the entire object to be used in the UI thread by clients of * WebView. This creates a copy that should never be modified by any of the * webkit package classes. On Android 4.4 and later there is no need to use * this, as the object is already a read-only copy of the internal state. */ protected abstract WebBackForwardList clone(); }

我们可以利用WebBackForwardList获取WebView的栈历史快照WebHistoryItem对象,这个对象里提供了获取页面url的方法。

/** * A convenience class for accessing fields in an entry in the back/forward list * of a WebView. Each WebHistoryItem is a snapshot of the requested history * item. * @see WebBackForwardList */ public abstract class WebHistoryItem implements Cloneable { ... /** * Return the url of this history item. The url is the base url of this * history item. See getTargetUrl() for the url that is the actual target of * this history item. * @return The base url of this history item. */ public abstract String getUrl(); ... }

三、解决方案

遍历栈列表获取各个栈快照对象,并解析得到一个栈url列表,值得注意的是,copyBackForwardList()和getCurrentIndex()需要在WebView创建线程(主线程)调用,而shouldInterceptRequest是在子线程中回调的,从而updateBackForwardList()不能直接shouldInterceptRequest中调用,也不建议通过线程阻塞的方式在shouldInterceptRequest中等待url栈解析完再进行拦截判断,毕竟除了要拦截的loadUrl,还有大量其他的请求也会在这里回调执行判断。

private List backForwardUrlList = new ArrayList(); private void updateBackForwardList() { backForwardUrlList.clear(); WebBackForwardList backForwardList = copyBackForwardList(); int currentIndex = backForwardList.getCurrentIndex(); for (int index = 0; index


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3